package controllers;

import static util.FindFoodUtil.empty;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import models.Category;
import models.Restaurant;
import models.State;
import play.Logger;
import play.cache.Cache;
import play.i18n.Messages;
import play.mvc.Controller;
import play.mvc.With;
import play.mvc.Scope.Params;
import util.Factual;
import util.IndexTank;
import util.MapAccessibleHelper;
import util.FindFoodUtil;

import com.flaptor.indextank.apiclient.IndexDoesNotExistException;
import com.flaptor.indextank.apiclient.IndexTankClient.Index;

@With(Common.class)
public class Listing extends Controller {

	public static void view(String docid) {
		if (empty(docid)) {
			flash.error(Messages.get("indextank.document.unavailable"));
			Application.index();
		}

		try {
			Index index = IndexTank.getRestaurantIndex();
			Factual factual = FindFoodUtil.getFactualClient();

			Restaurant r = Restaurant.get(index, docid);
			if (r == null) {
				flash.error(Messages.get("indextank.document.unavailable"));
				Application.index();
			}

			// Prevent reading from Factual more than once per hour per doc.
			Boolean factualReadTimeout = Cache.get("factualReadTimeout-" + docid,
					Boolean.class);
			if (factualReadTimeout == null || factualReadTimeout == false) {
				Cache.set("factualReadTimeout-" + docid, Boolean.TRUE, "1h");

				// Get the latest from Factual.
				Map<String, Object> factualValues = factual.read(docid);
				if (factualValues != null) {
					String subjectKey = (String) factualValues.remove("subject_key");
					Cache.set("subjectKey-" + docid, subjectKey);

					// If there are differences...
					Map<String, Object> differences = MapAccessibleHelper
							.getDifferences(r, factualValues);
					if (differences.size() > 0) {
						// ... Update IndexTank.
						MapAccessibleHelper.setFields(r, differences);
						try {
							r.updateIndexTank(index);
							Cache.set(r.getDocid(), r);
						} catch (IndexDoesNotExistException e) {
							Logger.error(e, "Could not update Restaurant.");
							throw new IOException(e);
						}
					}
				}
			}

			FindFoodUtil.loadCategories(renderArgs);
			FindFoodUtil.loadStates(renderArgs);
			render(r);
		} catch (IOException e) {
			flash.error(Messages.get("indextank.document.unavailable"));
			Application.index();
		}
	}

	public static void edit(String docid) {
		if (empty(docid)) {
			flash.error(Messages.get("indextank.document.unavailable"));
			Application.index();
		}

		State s = State.getByCode(params.get("state"));
		if (!empty(params.get("state")) && s == null) {
			validation.addError("state", Messages.get("state.invalid"));
		}
		if (validation.hasErrors()) {
			view(docid);
		}

		Map<String, Object> values = new HashMap<String, Object>();
		values.put("category", Category.getByValue(params.get("category"))
				.toString());
		values.put("address", params.get("address"));
		values.put("city", params.get("city"));
		values.put("state", (s != null) ? s.getCode() : null);
		values.put("postcode", params.get("zipcode"));
		values.put("website", params.get("website"));
		values.put("telephone", params.get("telephone"));
		values.put("fax", params.get("fax"));

		try {
			Index index = IndexTank.getRestaurantIndex();
			Restaurant r = Restaurant.get(index, docid);
			if (r == null) {
				flash.error(Messages.get("indextank.document.unavailable"));
				Application.index();
			}

			Map<String, Object> differences = MapAccessibleHelper.getDifferences(
					r, values);
			if (differences.size() > 0) {
				// Update Factual, but don't save the fields locally or to IndexTank.
				String subjectKey = Cache.get("subjectKey-" + docid, String.class);
				if (!empty(subjectKey)) {
					Factual factual = FindFoodUtil.getFactualClient();
					factual.write(subjectKey, differences);
					flash.success(Messages.get("factual.writeSucceeded"));
				} else {
					flash.error(Messages.get("factual.writeFailed"));
				}
				view(docid);
			}

		} catch (IOException e) {
			flash.error(Messages.get("indextank.document.unavailable"));
			Application.index();
		}
	}
}
